﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Runtime.InteropServices;

namespace TCPServer
{
    public partial class Form1 : Form
    {

        private static Socket client;
        private static byte[] data = new byte[1024];
        static Socket server;
        static string ClientName = "NULL_NAME";
        static string Value;
        static IPAddress address = IPAddress.Parse("127.0.0.1");
        static int port = 8000;

        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);

        [DllImport("user32")]
        public static extern int SetCursorPos(int x, int y);

        #region Fields
        private const int MOUSEEVENTF_MOVE = 0x0001; /* mouse move */
        private const int MOUSEEVENTF_LEFTDOWN = 0x0002; /* left button down */
        private const int MOUSEEVENTF_LEFTUP = 0x0004; /* left button up */
        private const int MOUSEEVENTF_RIGHTDOWN = 0x0008; /* right button down */
        private const int MOUSEEVENTF_RIGHTUP = 0x0010; /* right button up */
        private const int MOUSEEVENTF_MIDDLEDOWN = 0x0020; /* middle button down */
        private const int MOUSEEVENTF_MIDDLEUP = 0x0040; /* middle button up */
        private const int MOUSEEVENTF_XDOWN = 0x0080; /* x button down */
        private const int MOUSEEVENTF_XUP = 0x0100; /* x button down */
        private const int MOUSEEVENTF_WHEEL = 0x0800; /* wheel button rolled */
        private const int MOUSEEVENTF_VIRTUALDESK = 0x4000; /* map to entire virtual desktop */
        private const int MOUSEEVENTF_ABSOLUTE = 0x8000; /* absolute move */

        private SynchronizationContext context = null;
        private List<ClickObj> actions;
        #endregion

        public Form1()
        {
            InitializeComponent();
            context = SynchronizationContext.Current;
            actions = new List<ClickObj>();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            timer1.Enabled = true;
            try
            {
                server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint iep = new IPEndPoint(IPAddress.Parse(txtIPServer.Text), int.Parse(txtPort.Text));
                server.Bind(iep);
                server.Listen(5);
                Display("Server đã khởi động...");
                btnStart.Enabled = false;
                server.BeginAccept(new AsyncCallback(AcceptConnect), server);
            }
            catch (SocketException)
            {
                Display("Lỗi khởi tạo!");
            }
        }

        void AcceptConnect(IAsyncResult iar)
        {
                Socket oldserver = (Socket)iar.AsyncState;
                client = oldserver.EndAccept(iar);
                Thread nhandulieu = new Thread(new ThreadStart(Nhandulieu));
                nhandulieu.Start();
        }

        void Nhandulieu()
        {
            int recv;

            recv = client.Receive(data);
            if (recv != 0)
            {
                ClientName = Encoding.ASCII.GetString(data, 0, recv);
            }
            try
            {
                Display("Client " + ClientName + " đã kết nối. IP: " + client.RemoteEndPoint.ToString());
                while (true)
                {
                    recv = client.Receive(data);
                    if (recv == 0)
                    {
                        Display("Client " + ClientName + " hủy kết nối. IP: " + client.RemoteEndPoint.ToString());
                        client.Close();                     
                        server.BeginAccept(new AsyncCallback(AcceptConnect), server);
                        return;
                    }
                    Value = Encoding.ASCII.GetString(data, 0, recv);
                    string[] s;
                    s = Value.Split('|');
                    
                    if (s[0] == "1")
                    {     
                    //    s[0] = "Nhấn Chuột";
                    }
                    else
                    {
                        actions.Add(new ClickObj(int.Parse(s[0]), 0, s[2], 0, 0));
                        s[0] = "Nhấn Phím";
                        DisplayRev(s);
                    }

                    if (s[1] == "1")
                    {
                        actions.Add(new ClickObj(int.Parse(s[0]), int.Parse(s[1]), s[2], int.Parse(s[3]), int.Parse(s[4])));
                        s[0] = "Nhấn Chuột";
                        s[1] = "Click Đơn";
                        DisplayRev(s);
                    }
                    else
                        if (s[1] == "2")
                        {
                            actions.RemoveAt(actions.Count - 1);
                            actions.Add(new ClickObj(int.Parse(s[0]), int.Parse(s[1]), s[2], int.Parse(s[3]), int.Parse(s[4])));
                            s[0] = "Nhấn Chuột";
                            s[1] = "Click Đôi";
                            DisplayDouble(s);
                        }         
                }
            }
            catch (SocketException)
            {
                Display("Lỗi nhận dữ liệu!");
            }
            
            Display("Client " + ClientName + " hủy kết nối. IP: " + client.RemoteEndPoint.ToString());
            client.Close();

        }

        private delegate void DlDisplay(string s);
        private delegate void Dl2DisPlay(string[] s);
        private void Display(string s)
        {
            if (lsbKetNoi.InvokeRequired)
            {
                DlDisplay sd = new DlDisplay(Display);
                lsbKetNoi.Invoke(sd, new object[] { s });
            }
            else
            {
                lsbKetNoi.Items.Add(s);
            }
        }

        private void DisplayRev(string[] s)
        {
            if (lsbKetNoi.InvokeRequired)
            {
                try
                {
                    Dl2DisPlay sd = new Dl2DisPlay(DisplayRev);
                    lsRev.Invoke(sd, new object[] { s });
                }
                catch (Exception ex)
                {

                }
            }
            else
            {
                lsRev.Items.Add(new ListViewItem(new string[]{s[0],s[1],s[2],s[3],s[4]}));
            }
        }

        private void DisplayDouble(string[] s)
        {
            if (lsbKetNoi.InvokeRequired)
            {
                Dl2DisPlay sd = new Dl2DisPlay(DisplayDouble);
                lsRev.Invoke(sd, new object[] { s });
            }
            else
            {
                lsRev.Items.RemoveAt(lsRev.Items.Count - 1);
                lsRev.Items.Add(new ListViewItem(new string[] { s[0], s[1], s[2], s[3], s[4] }));
            }
        }

        private void DisplayRemove(string s)
        {
            if (lsbKetNoi.InvokeRequired)
            {
                DlDisplay sd = new DlDisplay(DisplayRemove);
                lsRev.Invoke(sd, new object[] { s });
            }
            else
            {
                lsRev.Items.RemoveAt(0);
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (actions.Count > 0)
            {
                RunAction();
            }
        }

        private void RunAction()
        {
                if (actions[0].Type.Equals(2))
                {
                    ThreadPool.QueueUserWorkItem(new WaitCallback(WorkSendKeys), actions[0]);
                }
                else
                {
                    ThreadPool.QueueUserWorkItem(new WaitCallback(WorkClick), actions[0]);
                }
        }
        private void WorkSendKeys(object state)
        {
            this.context.Send(new SendOrPostCallback(delegate(object _state)
            {
                ClickObj action = state as ClickObj;
                SendKeys.Send(action.Data);
                actions.RemoveAt(0);
                DisplayRemove("");
            }), state);
        }
        private void WorkClick(object state)
        {
            this.context.Send(new SendOrPostCallback(delegate(object _state)
            {
                ClickObj action = state as ClickObj;
                SetCursorPos(action.X, action.Y);
                Thread.Sleep(100);
                switch (action.Style)
                {
                    case 1:
                        if (action.Data == "Left")
                        {
                            mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
                            mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
                        }
                        else
                            if (action.Data == "Right")
                            {
                                mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);
                                mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
                            }
                            else
                            {
                                mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, 0);
                                mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, 0);
                            }
                        actions.RemoveAt(0);
                        DisplayRemove("");
                        break;                     
                    case 2:
                        if (action.Data == "Left")
                        {
                            mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
                            mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
                            Thread.Sleep(100);
                            mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
                            mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
                        }
                        else
                            if (action.Data == "Right")
                            {
                                mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);
                                mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
                                Thread.Sleep(100);
                                mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);
                                mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
                            }
                            else
                            {
                                mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, 0);
                                mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, 0);
                                Thread.Sleep(100);
                                mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, 0);
                                mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, 0);
                            }
                        actions.RemoveAt(0);
                        DisplayRemove("");
                        break;        
                }
            }), state);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            txtIPServer.Text = address.ToString();
            txtPort.Text = port.ToString();
        }
    }
}
